package org.redhat.auth.security.core;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.redhat.auth.security.user.UserDetailInfo;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

/**
 * 自定义实现的一个Filter,用于实现SPRING SECURITY用户从数据库中读取，资源定义从数据库中读取，决策自实现三个功能
 * 
 * @author lingen.liu
 * 
 */
public class AuthDefaultFilterSecurityInterceptor extends
		AbstractSecurityInterceptor implements Filter {

	public AuthDefaultFilterSecurityInterceptor() {
		setAccessDecisionManager(new AccessDecisionManager() {
			public void decide(Authentication authentication, Object object,
					Collection<ConfigAttribute> configAttributes)
					throws AccessDeniedException,
					InsufficientAuthenticationException {
				/* 测试用户不进行权限限制 */
				Object o = SecurityContextHolder.getContext()
						.getAuthentication().getPrincipal();
				if (o instanceof UserDetailInfo) {
					UserDetailInfo user = (UserDetailInfo) o;
					if (user.isTestUser()) {
						return;
					}
					for (Iterator<ConfigAttribute> ite = configAttributes
							.iterator(); ite.hasNext();) {
						ConfigAttribute ca = ite.next();
						if (user.hasAuthorize(ca.getAttribute())) {
							return;
						}
					}
				}
				throw new AccessDeniedException("no right");
			}

			public boolean supports(ConfigAttribute paramConfigAttribute) {
				return true;
			}

			public boolean supports(Class<?> paramClass) {
				return true;
			}
		});
	}

	public Class<? extends Object> getSecureObjectClass() {
		return FilterInvocation.class;
	}

	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return new FilterInvocationSecurityMetadataSource() {
			public Collection<ConfigAttribute> getAllConfigAttributes() {
				return new HashSet<ConfigAttribute>();
			}

			public Collection<ConfigAttribute> getAttributes(Object object)
					throws IllegalArgumentException {
				HashSet<ConfigAttribute> hashSet = new HashSet<ConfigAttribute>();
				String url = ((FilterInvocation) object).getRequestUrl();
				hashSet.add(new SecurityConfig(url));
				return hashSet;
			}

			public boolean supports(Class<?> paramClass) {
				return true;
			}
		};
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {
		FilterInvocation fi = new FilterInvocation(request, response,
				filterChain);
		invoke(fi);
	}

	public void invoke(FilterInvocation fi) throws IOException,
			ServletException {
		InterceptorStatusToken token = null;
		Object o = SecurityContextHolder.getContext().getAuthentication()
				.getPrincipal();
		if (o != null && o instanceof UserDetailInfo) {
			token = super.beforeInvocation(fi);
		}
		try {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}

	}

	public void destroy() {
	}

	public void init(FilterConfig arg0) throws ServletException {

	}

}